package main;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.rmi.AccessException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.UnmarshalException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

import org.apache.commons.lang3.SystemUtils;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Level;
import org.apache.log4j.PatternLayout;
import org.apache.zookeeper.AsyncCallback.StatCallback;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;

import window.Console;
import comunicacao.GestorZooKeeper;
import comunicacao.MessageRedirectorInterface;
import comunicacao.primaryDBInterface;
import entities.CachedTeatro;
import entities.ConfigInfo;
import entities.Range;
import entities.ServerInfo;
import entities.Teatro;

/**
 * Controlador principal da base de dados. Gere a conexao com o ZooKeeper
 * e e responsavel pelas funcoes de uma base de dados primaria
 * 
 * @author Leonardo Lino Nº45340
 * @author Diogo Pires Nº40351
 */
public class DBmaster extends java.rmi.server.UnicastRemoteObject implements
		Watcher, MessageRedirectorInterface, primaryDBInterface {

	public static final int SHARDING_LEVEL_0 = 0;
	public static final int SHARDING_LEVEL_1 = 1;
	public static final int SHARDING_LEVEL_2 = 2;
	
	public final boolean USE_FILE_ADDRESS = true;
	private boolean disabled;
	
	private Registry registry;
	private DBmanager database;
	private GestorZooKeeper zKeeper;
	private String zKeeperAddressPort;
	private MembershipManager mManager;
	private Watcher eWatcher;
	
	private final String CURRENT_DIR;
	private final String RUNNING_LOCATION;
	private final String OS;
	private final String CONFIG_FILE = "config.txt";
	private final int SESSION_TIMEOUT = 5000;
	private String eol = System.lineSeparator();
	
	private boolean fileOverride;
	private String thisAddress;
	private String thisfileAddress;
	private String baseLocation;
	private int thisPort;
	private int rows;
	private int columns;
	private int numtheaters;
	private int cacheLimit;
	
	private int server_id;
	private String dbRegistryName;
	private boolean isLeader;
	private int leaderPort;
	private String leaderAddress;
	private String leaderBindName;
	private int leaderID;
	
	private int serverCount;
	private Object signal;
	private ArrayList<String> nodeData;
	private ArrayList<ServerInfo> servers;
	private ArrayList<ServerInfo> serversOrder; // NAO ESTA A SER USADO
	private ArrayList<ServerInfo> serversInMaintenance;
	private LinkedHashMap<String, Integer> theatersMap;
	Thread DBHandler;
	
	public DBmaster() throws RemoteException{
		disabled = false;
		
		String everything = "";
		OS = SystemUtils.OS_NAME;
		ConfigInfo config = new ConfigInfo();
		
		CURRENT_DIR = System.getProperty("user.dir") + File.separator;

		if(SystemUtils.IS_OS_LINUX){
			String temp = FileOperator.path(new File(this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath()), true,true);
			RUNNING_LOCATION = temp.replace("%20"," ");
		}else if(SystemUtils.IS_OS_WINDOWS)
			RUNNING_LOCATION = CURRENT_DIR;
		else
			RUNNING_LOCATION = FileOperator.path(new File(this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath()), true,true);
		
		
		System.out.println("Operating System: " + OS);
		System.out.println("Execution File Directory: "+RUNNING_LOCATION);
		System.out.println("Current Directory: "+CURRENT_DIR);
		
		
		// Open config file
		try {
			File file = new File(RUNNING_LOCATION + CONFIG_FILE);
			
			FileReader fr = new FileReader(file);
			BufferedReader br = new BufferedReader(fr);

			StringBuilder sb = new StringBuilder();
			String line = br.readLine();

			while (line != null) {
				sb.append(line);
				sb.append(eol);
				line = br.readLine();
			}

			br.close();
			everything = sb.toString();
		} catch (IOException e) {
		}

		String args[] = everything.split("\\s+");

		// Load config file
		for (int i = 0; i < args.length; i++) {
			String[] lineChunks = args[i].split(":");
			if (lineChunks[0].equals("Port")){
				thisPort = Integer.parseInt(lineChunks[1]); // (registry port)
				config.setThisPort(thisPort);
			}else if (lineChunks[0].equals("Storage")) {
				if (lineChunks.length != 1) {
					baseLocation = lineChunks[1];
					config.setBaseLocation(baseLocation);
				} else{
					baseLocation = "";
					config.setBaseLocation(baseLocation);
				}
			} else if (lineChunks[0].equals("NumberTheaters")){
				numtheaters = Integer.parseInt(lineChunks[1]);
				config.setNumtheaters(numtheaters);
			}else if (lineChunks[0].equals("Rows")){
				rows = Integer.parseInt(lineChunks[1]);
				config.setRows(rows);
			}else if (lineChunks[0].equals("Columns")){
				columns = Integer.parseInt(lineChunks[1]);
				config.setColumns(columns);
			}else if (lineChunks[0].equals("CacheTime")){
				cacheLimit = Integer.parseInt(lineChunks[1]);
				config.setCacheLimit(cacheLimit);
			}else if (lineChunks[0].equals("Override")){
				fileOverride = Boolean.parseBoolean(lineChunks[1]);
				config.setFileOverride(fileOverride);
			}else if (lineChunks[0].equals("ZooKeeper")){
				zKeeperAddressPort = lineChunks[1] + ":" + lineChunks[2];
			}else if (lineChunks[0].equals("Address")){
				thisfileAddress = lineChunks[1];
			}
		}
		
		if(USE_FILE_ADDRESS){
			thisAddress = thisfileAddress;
		}else{
			try {
				// get the address of this host.
				thisAddress = (InetAddress.getLocalHost().getHostAddress());
			} catch (UnknownHostException e) {
				System.out.println("Error: could not retrieve Host Address");
			}
		}

		System.out.println("this address=" + thisAddress + ", port=" + thisPort);
		System.out.println("----------------------------------------------------" + eol);

		config.setThisAddress(thisAddress);
		
		genTheatersHash();
		
		servers = new ArrayList<ServerInfo>();
		serversOrder = new ArrayList<ServerInfo>();
		serversInMaintenance = new ArrayList<ServerInfo>();
		nodeData = new ArrayList<String>();
		
		eWatcher = this;
		
		startZooKeeperClient(zKeeperAddressPort);
		
		nodeData.add(thisAddress+":"+Integer.toString(thisPort)+":dbServer"+Integer.toString(server_id));
		nodeData.add(Integer.toString(server_id));
		config.setId(server_id);

		if(!isLeader){
			signal = new Object();
			ServerInfo leaderInfo = new ServerInfo(leaderAddress, leaderPort, leaderID);
			leaderInfo.setBindName(leaderBindName);
			startDatabase(DBHandler, config, signal, zKeeper, leaderInfo);
			
			synchronized (signal) {
				try {
					signal.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			
			nodeData.add("ready");
			zKeeper.setData("/DBServers/DB-"+Integer.toString(server_id), nodeDataToString(nodeData), -1);
		}else{
			try {
				dbRegistryName = "dbServer" + Integer.toString(server_id);
				// create the registry and bind the name and object.
				registry = LocateRegistry.createRegistry(thisPort);
				registry.rebind(dbRegistryName, this);
			} catch (RemoteException e) {
				System.out.println("ERROR: could not create master registry");
				e.printStackTrace();
				throw e;
			}
		}
	}
	
	private void startDatabase(Thread thread,ConfigInfo config, Object signal, GestorZooKeeper zKeeper, ServerInfo leaderInfo){
		Runnable task = new DBThread(config, signal, zKeeper, leaderInfo);
		thread = new Thread(task);
		thread.setName("DBHandler");
		thread.start();
	}
	
	private boolean startZooKeeperClient(String addressPort){
		System.out.println("------------STARTING ZOOKEEPER CLIENT------------");
		
		boolean result = true;
		zKeeper = new GestorZooKeeper();
		mManager = new MembershipManager(zKeeper, eWatcher);
		
		try {
			  ConsoleAppender console = new ConsoleAppender(); //create appender
			  //configure the appender
			  String PATTERN = "%d [%p|%c|%C{1}] %m%n";
			  console.setLayout(new PatternLayout(PATTERN)); 
			  console.setThreshold(Level.ERROR);
			  console.activateOptions();
			  //add appender to any Logger (here is root)
			  //Logger.getRootLogger().addAppender(console);
			
			org.apache.log4j.BasicConfigurator.configure(console);
			zKeeper.connect(addressPort, SESSION_TIMEOUT);
		} catch (IOException | InterruptedException e) {
			System.out.println("Error while connecting to ZooKeeper service");
			e.printStackTrace();
			result = false;
		}
		
		if (result) {
			
			if(!mManager.checkGlobalGroup(null))
				mManager.createGlobalGroup();
			
			if(!mManager.checkGlobalConfig(null))
				mManager.createGlobalConfig(Integer.toString(numtheaters));
			
			// Cria o grupo base para as Bases de Dados
			// Adiciona uma watch
			if (!mManager.checkDBGroup(null))
				mManager.createDBGroup();

			// Cria o grupo Ready
			if (!mManager.checkReadyGroup(null))
				mManager.createReadyGroup();

			if(!mManager.checkIDTracker(null)){
				if(mManager.createIDTracker()){
					server_id = 1;
					mManager.setCurrentID(Integer.toString(server_id));
				}else{
					result = false;
				}
			}else{
				String current = mManager.getCurrentID(null);
				
				if(current != null){
					server_id = Integer.parseInt(current) + 1;
					mManager.setCurrentID(Integer.toString(server_id));
				}else{
					result = false;
					System.out.println("Error: Could not retrieve current ID");
				}
			}
			
			// Adiciona-se ao grupo de servidores
			if (!mManager.JoinDBGroup(Integer.toString(server_id), thisAddress, thisPort)){
				result = false;
				isLeader = false;
				System.out.println("Failed joining process");
			}else {
				// Cria o sinalizador Ready das Bases de Dados
				// Adiciona uma watch
				if (!mManager.checkDBReady(null)) {
					if (mManager.createDBReady()){
						mManager.setDBReadyData(thisAddress,
								Integer.toString(thisPort),
								Integer.toString(server_id));
						isLeader = true;
					}else
						result = false;
				} else {
					isLeader = false;
					String data = mManager.getDBReadyData(null);
					if (data != null) {
						try {
							String[] dataParts = data.split(",");
							leaderAddress = dataParts[0].split(":")[0];
							leaderPort = Integer.parseInt(dataParts[0]
									.split(":")[1]);
							leaderBindName = dataParts[0].split(":")[2];
							leaderID = Integer.parseInt(dataParts[1]);
						} catch (Exception e) {
							System.out.println("Error reading data");
							e.printStackTrace();
						}
					} else {
						System.out.println("Ready DB data was null");
						result = false;
					}
				}
			}
		}
		
		if(isLeader){
			zKeeper.setGroupWatcher("/DBServers", eWatcher);
		}
		
		System.out.println();
		System.out.println("Server ID: " + server_id);
		System.out.println("Leader status: " + isLeader);
		System.out.println("ZooKeeper initial connection setup: " + result);
		
		System.out.println("----------------------------------------------------------------------");
		return result;
	}
	
	private void genTheatersHash() {
		theatersMap = new LinkedHashMap<String, Integer>(500);
		String name;

		for (int i = 1; i <= numtheaters; i++) {
			name = "teatro" + Integer.toString(i);
			theatersMap.put(name, i);
		}
	}
	
	//Selects a database server to provide data to a new database server
	public ServerInfo selectProvider() {
		ServerInfo server = null;
		int largestRange = 0;
		
		ArrayList<ServerInfo> availableServers = new ArrayList<ServerInfo>();
		
		for(ServerInfo serv: servers){
			if(serv.isAvailable()){
				availableServers.add(serv);
			}
		}
		
		if(availableServers.size() != 0){
			for(ServerInfo serv: availableServers){
					if(serv.getMainRange().getSize() > largestRange){
						server = serv;
						largestRange = serv.getMainRange().getSize();
					}
			}
		}
		
		return server;
	}
	
	public ServerInfo getProviderReplic(int providerID){
		ServerInfo server = null;
		
		for(ServerInfo serv: servers){
			if(serv.isAvailable()){
				if(serv.getCoordinatorRange().getResponsable() == providerID){
					server = serv;
					break;
				}
			}
		}
		
		return server;
	}
	
	public ServerInfo getProviderCoordinator(int providerID){
		ServerInfo server = null;
		
		for(ServerInfo serv: servers){
			if(serv.isAvailable()){
				if(serv.getReplicRange().getResponsable() == providerID){
					server = serv;
					break;
				}
			}
		}
		
		return server;
	}
	
	public String nodeDataToString(ArrayList<String> node){
		StringBuilder sb = new StringBuilder();
		
		for(int i=0; i<node.size(); i++){
			
			if(i != node.size() -1){
				sb.append(node.get(i));
				sb.append(',');
			}else
				sb.append(node.get(i));
		}
		
		return sb.toString();
	}
	
	@Override
	public void process(WatchedEvent event) {
		switch (event.getType()) {
		case NodeChildrenChanged:
			System.out.println(eol + "-----------------------EVENT------------------------");
			System.out.println("Reveived children change event");
			System.out.println("Location: " + event.getPath());
			
			System.out.println("Children list:");
			List<String> childrens = zKeeper.listGroup(event.getPath(), this);
			
			if(childrens != null)
				for (String child : childrens) {
					System.out.println("    -" + child);
				}
			
			for(String str: childrens){
				boolean found = false;
				
				//Se nao for o id node ou o primary
				if(!str.equals("ID") && !str.equals("DB-"+Integer.toString(server_id)) ){
					String idStr = str.split("-")[1];
					int id = Integer.parseInt(idStr);
					
					//verifica se ja e conhecido
					for (ServerInfo serv : servers) {
						if (serv.getId() == id) {
							found = true;
							break;
						}
					}
					
					//Se nao for conhecido
					if(!found){
						String data = zKeeper.getData("/DBServers/DB-" + idStr, -1, null);
						String[] dataParts = data.split(",");
						String address = dataParts[0].split(":")[0];
						int port = Integer.parseInt(dataParts[0].split(":")[1]);
						
						ServerInfo newServer = new ServerInfo(address, port, id);
						newServer.setAvailable(false);
						newServer.setBindName("dbServer"+ idStr);
						
						zKeeper.existsZNode("/DBServers/DB-" + idStr, this);
						servers.add(newServer);
						
						System.out.println(eol + "New database server found!");
						System.out.println("server " + "DB-" + idStr + " added to list");
					}
				}
			}
			
			System.out.println("--------------------------------------------------------");
			
			break;

		case NodeCreated:
			System.out.println("Node Created :" + event.getPath());
			break;

		case NodeDataChanged:
			System.out.println(eol + "-----------------------EVENT------------------------");
			System.out.println("Reveived node data change event");
			System.out.println("Location: " + event.getPath() + eol);
			String data = zKeeper.getData(event.getPath(), -1, null);
			String[] dataParts = data.split(",");
			
			if(dataParts.length > 2){
				if(dataParts[2].equals("ready")){
					
					//Vai encontrar o servidor correspondente ao evento (guardado)
					for(int i = 0; i< servers.size(); i++){
						if(servers.get(i).getId() == Integer.parseInt(dataParts[1])){
							
							System.out.println("Server DB-" + servers.get(i).getId() + " is ready for inicialization");
							
							//Se for o primeiro servidor
							if(servers.size() == 1){
								System.out.println("sending level 0 start conditions (FIRST SERVER)");
								Range range = new Range(1, numtheaters, servers.get(i).getId());
								
								servers.get(i).setMainRange(range);

								
								servers.get(i).setAvailable(false);
								servers.get(i).setInMaintenance(true);
								
								serversInMaintenance.add(servers.get(i));
								
								MasterUtils.sendStartConditions(servers.get(i), null, null, null, range, null, null, SHARDING_LEVEL_0);
								
								//servers.get(i).setAvailable(true);
								
							}//Se nao for o primeiro servidor
							else{
								if(servers.size() == 2){
									System.out.println("sending level 1 start conditions (SECOND SERVER)");
									
									ServerInfo provider = selectProvider();
									System.out.println(eol + "selected provider is: DB-" + provider.getId());
									
									Range range = MasterUtils.calculateMainRange(provider.getMainRange(), servers.get(i).getId());
									Range coordinatorRange = MasterUtils.calculateReplicRange(provider.getMainRange(), provider.getId());
									Range replicRange = MasterUtils.calculateMainRange(provider.getMainRange(), provider.getId());;
									Range providerReplicRange = MasterUtils.calculateReplicRange(provider.getMainRange(), servers.get(i).getId());

									servers.get(i).setMainRange(range); //Data hold by this server
									servers.get(i).setReplicRange(replicRange); //Data replicated from this server
									servers.get(i).setCoordinatorRange(coordinatorRange); //Data this server replicates
									servers.get(i).setIdReplic(replicRange.getResponsable());// replica id
									servers.get(i).setIdCoordinator(coordinatorRange.getResponsable()); //coordinator id
									
									provider.setMainRange(coordinatorRange);
									provider.setReplicRange(providerReplicRange);
									provider.setCoordinatorRange(range);
									provider.setIdReplic(providerReplicRange.getResponsable());
									provider.setIdCoordinator(range.getResponsable());

									
									servers.get(i).setAvailable(false);
									servers.get(i).setInMaintenance(true);
									
									provider.setAvailable(false);
									provider.setInMaintenance(true);
									
									serversInMaintenance.add(servers.get(i));
									serversInMaintenance.add(provider);
									
									MasterUtils.sendStartConditions(servers.get(i), provider, null, null, range, coordinatorRange, replicRange, SHARDING_LEVEL_1);
									
									//servers.get(i).setAvailable(true);
									
								}else{
									System.out.println("sending level 2 start conditions (> TWO SERVERS)");
									
									ServerInfo provider = selectProvider();
									ServerInfo providerReplic = getProviderReplic(provider.getId());
									ServerInfo coordinator = getProviderCoordinator(provider.getId());
									
									System.out.println(eol + "selected provider is: DB-" + provider.getId());
									System.out.println("    provider replic is: DB-" + providerReplic.getId());
									System.out.println("    provider coordinator is: DB-" + coordinator.getId());
									
									Range range = MasterUtils.calculateMainRange(provider.getMainRange(), servers.get(i).getId());
									Range coordinatorRange = provider.getCoordinatorRange();
									Range replicRange = MasterUtils.calculateMainRange(provider.getMainRange(), provider.getId());;
									
									Range providerMainRange = MasterUtils.calculateReplicRange(provider.getMainRange(), provider.getId());
									Range providerReplicRange = MasterUtils.calculateReplicRange(provider.getMainRange(), provider.getIdReplic());

									Range coordinatorReplicRange =  new Range(coordinatorRange.getMin(), coordinatorRange.getMax(), servers.get(i).getId());
									
									servers.get(i).setMainRange(range); //Data hold by this server
									servers.get(i).setReplicRange(replicRange); //Data replicated from this server
									servers.get(i).setCoordinatorRange(coordinatorRange); //Data this server replicates
									
									servers.get(i).setIdReplic(replicRange.getResponsable());// replica id
									servers.get(i).setIdCoordinator(coordinatorRange.getResponsable()); //coordinator id
									
									provider.setMainRange(providerMainRange);
									provider.setReplicRange(providerReplicRange);
									provider.setCoordinatorRange(range);
									
									provider.setIdReplic(providerReplicRange.getResponsable());
									provider.setIdCoordinator(range.getResponsable());
									
									providerReplic.setCoordinatorRange(providerMainRange);
									
									providerReplic.setIdCoordinator(providerMainRange.getResponsable());
									
									coordinator.setReplicRange(coordinatorReplicRange);
									coordinator.setIdReplic(coordinatorReplicRange.getResponsable());
									
									
									servers.get(i).setAvailable(false);
									servers.get(i).setInMaintenance(true);
									
									provider.setAvailable(false);
									provider.setInMaintenance(true);
									
									providerReplic.setAvailable(false);
									providerReplic.setInMaintenance(true);
									
									coordinator.setAvailable(false);
									coordinator.setInMaintenance(true);
									
									
									serversInMaintenance.add(servers.get(i));
									serversInMaintenance.add(provider);
									serversInMaintenance.add(providerReplic);
									if(providerReplic.getId() != coordinator.getId())
										serversInMaintenance.add(coordinator);
									
									MasterUtils.sendStartConditions(servers.get(i), provider, providerReplic, coordinator, range, coordinatorRange, replicRange, SHARDING_LEVEL_2);
									
									//servers.get(i).setAvailable(true);
									
								}
							}
						}
					}
				}
			}
			
			System.out.println("--------------------------------------------------------");
			
			break;

		case NodeDeleted:
			System.out.println("Node Deleted :" + event.getPath());
			break;

		default:
			break;
		}
	}
	
	public String getResponsible(String theaterName) throws RemoteException{
		String result = null;
		
		//System.out.println("Receive Request for " + theaterName);
		
		for(ServerInfo serv: servers){
			if(serv.isAvailable()){
				if(isInRange(serv.getMainRange().getMin(), serv.getMainRange().getMax(), theaterName)){
					result = serv.getAddress() +":"+ Integer.toString(serv.getPort()) +":"+ serv.getBindName();
					break;
				}
			}
		}
		
		/*
		if(result != null)
			System.out.println("Redirected to " + result);
		else
			System.out.println("Redirected to null");
		*/
		return result;
	}
	
	public String listTheaters() throws RemoteException {
		String result = null;
		
		//System.out.println("Receive Request for list of theaters");
		
		for(ServerInfo serv: servers){
			if(serv.isAvailable())
				result = serv.getAddress() +":"+ Integer.toString(serv.getPort()) +":"+ serv.getBindName();
		}
		
		/*
		if(result != null)
			System.out.println("Redirected to " + result);
		else
			System.out.println("Redirected to null");
		*/
		
		return result;
	}

	private boolean isInRange(int min, int max, String theaterName){
		boolean result = false;
		Integer teatroID;
		
		try {
			teatroID = theatersMap.get(theaterName);
			
			if(teatroID != null)
				if(teatroID >= min && teatroID <= max)
					result = true;
			
		} catch (NullPointerException e) {
			result = false;
		}
		
		return result;
	}
	
	public boolean setReady(int serverID) throws RemoteException {
		boolean result = true;
		
		for(ServerInfo serv: serversInMaintenance){
			if(serv.getId() == serverID){
				serv.setInMaintenance(false);
				System.out.println(eol + "DB-" + serverID + " finished maintenance");
			}
		}
		
		if(areAllReadyInMaintenance()){
			System.out.println(eol + "All servers in maintenance are now available");
			
			for(ServerInfo serv: serversInMaintenance){
				System.out.println("    - DB-" + serv.getId());
				serv.setAvailable(true);
			}
			serversInMaintenance.clear();
			System.out.println();
		}
		
		return result;
	}
	
	private boolean areAllReadyInMaintenance(){
		boolean result = false;
		int nServers = serversInMaintenance.size();
		int count = 0;
		
		for(ServerInfo serv: serversInMaintenance){
			if(!serv.isInMaintenance())
				count ++;
		}
		
		if(count == nServers)
			result = true;
		
		return result;
	}
	
	public boolean falha() throws RemoteException {
		System.out.println("Received: system failure request");
		shutDownServerRegistry(true);
		return disabled = true;
	}
	
	private void shutDownServerRegistry(boolean failure) throws RemoteException {
		int succesful = 0;

		if (!failure)
			try {
				registry.unbind(dbRegistryName);
				UnicastRemoteObject.unexportObject(this, true);
			} catch (NotBoundException e) {
				succesful = -1;
			} catch (AccessException e) {
				succesful = -1;
			} catch (UnmarshalException e) {
				System.out.println(e.detail.getMessage());
				succesful = -1;
			} catch (RemoteException e) {
				System.out.println(e.detail.getMessage());
				succesful = -1;
			}
		else {
			try {
				registry.unbind(dbRegistryName);
				registry.rebind(dbRegistryName + "temp", this);
			} catch (RemoteException e) {
				System.out.println("Error: failure mode rebind could not be completed");
				throw e;
			} catch (NotBoundException e) {
				succesful = -1;
			}
		}

		// System.exit(succesful);
	}
	
	public boolean restart() throws RemoteException {
		System.out.println("Received: system restart request");
		disabled = false;
		restartServerRegistry();
		return (!disabled);
	}
	
	private void restartServerRegistry() throws RemoteException {
		try {
			registry.unbind(dbRegistryName + "temp");
			registry.rebind(dbRegistryName, this);
		} catch (RemoteException e) {
			throw e;
		} catch (NotBoundException e) {
		}
	}

	public static void main(String args[]) {

		try {
			new Console();
			DBmaster db = new DBmaster();
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		}

	}
	
}
